home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / svgakt50.zip / SRC / SVGAKIT / CPU.ASM next >
Assembly Source File  |  1994-08-23  |  12KB  |  303 lines

  1. ;****************************************************************************
  2. ;*
  3. ;*                            The MegaToolbox
  4. ;*
  5. ;*                  Copyright (C) 1993 SciTech Software
  6. ;*                          All rights reserved.
  7. ;*
  8. ;* Filename:    $RCSfile: cpu.asm $
  9. ;* Version:     $Revision: 1.1 $
  10. ;*
  11. ;* Language:    8086 Assembler
  12. ;* Environment: IBM PC Real Mode and 16 bit Protected Mode.
  13. ;*
  14. ;* Description: Autodetection routine to determine the type of CPU installed
  15. ;*              in the system.
  16. ;*
  17. ;* $Id: cpu.asm 1.1 1994/08/22 12:27:00 kjb release $
  18. ;*
  19. ;****************************************************************************
  20.  
  21.         IDEAL
  22.  
  23. INCLUDE "model.mac"             ; Memory model macros
  24.  
  25. header  cpu                     ; Set up memory model
  26.  
  27. ;****************************************************************************
  28. ;
  29. ; Equates used by queryCPU routine.
  30. ;
  31. ;****************************************************************************
  32.  
  33. ; Central Processing Unit type codes
  34.  
  35. CPU86       =   0               ; 8086/88 type processor
  36. CPU186      =   1               ; 80186 type processor
  37. CPU286      =   2               ; 80286 type processor
  38. CPU286p     =   3               ; 80286 type processor in protected mode
  39. CPU386      =   4               ; 80386 type processor
  40. CPU386p     =   5               ; 80386 type processor in protected mode
  41. CPU486      =   6               ; 80486 type processor
  42. CPU486p     =   7               ; 80486 type processor in protected mode
  43. CPU586        =    8                ; Pentium type processor
  44. CPU586p        =    9                ; Pentium type processor in protected mode
  45.  
  46. ; Floating Point Unit type codes
  47.  
  48. FPUNONE     =   0               ; No coprocessor present
  49. FPU87       =   1               ; 8087 coprocessor
  50. FPU287      =   2               ; 80287 coprocessor
  51. FPU387      =   3               ; 80387 coprocessor
  52. FPU487      =   4               ; 80487 coprocessor
  53. FPU587        =    5                ; Pentium coprocessor
  54.  
  55. ; Save the type of CPU detected so we can determine the co-processor
  56. ; type correctly. This means that we MUST call queryCpu() BEFORE calling
  57. ; queryFpu() to obtain correct results.
  58.  
  59. begdataseg
  60. cpu         dw  CPU86
  61. enddataseg
  62.  
  63. begcodeseg  cpu                 ; Start of code segment
  64.  
  65. P386                            ; Turn on 386 instructions
  66.  
  67. ;----------------------------------------------------------------------------
  68. ; cpu_type queryCpu(void)
  69. ;----------------------------------------------------------------------------
  70. ; Determine type of processor present.
  71. ;----------------------------------------------------------------------------
  72. procstart   _queryCpu
  73.  
  74.         push    bx
  75.         push    bp              ; We MUST save bp for initialization code...
  76.  
  77.         mov     _ax,CPU86       ; Default to 8086/8088 processor
  78.         push    sp
  79.         pop     bx              ; BX holds the value of SP or SP-2
  80.         cmp     bx,sp           ; 88/86/186 pushes the value of SP-2
  81.         je      @@Check286      ; Must be a 286/386/486 type processor
  82.         mov     cl,32           ; 186 uses count mod 32 = 0
  83.         shl     bx,cl           ; 86 shifts 32 bits left so ax = 0
  84.         jz      @@Done          ; zero: shifted out all bits so 86/88
  85.         mov     _ax,CPU186      ; nonzero: no shift, so 186
  86.         jz      @@Done
  87.  
  88. @@Check286:                     ; First check for 386/486 in 32 bit mode
  89.         pushf                   ; Test for 16 or 32 operand size:
  90.         mov     bx,sp           ;  pushed 2 or 4 bytes of flags
  91.         popf
  92.         inc     bx
  93.         inc     bx
  94.         cmp     bx,sp           ; did pushf change sp by 2?
  95.         jnz     @@Check486      ; 32 bit push, so it is a 386/486
  96.  
  97.         sub     sp,6            ; Is it a 286/386/486 in 16 bit mode?
  98.         mov     bp,sp
  99.         sgdt    [QWORD ptr bp]  ; 80286/386/486 specific instrucion
  100.         add     sp,4            ; Get global descriptor table
  101.         pop     bx
  102.         inc     bh              ; Third word of GDT = -1 for 286
  103.         jnz     @@Check486      ; We have a 386/486
  104.  
  105.         mov     _ax,CPU286      ; We have a 286
  106.         jmp     @@TestPROT
  107.  
  108. @@Check486:
  109.  
  110. ; Distinguish an 80386 from an 80486. Bit 18 (40000H) of EFLAGS register
  111. ; is used only in the 486. This code flips it and tests if anything happened.
  112.  
  113.         mov     edx,esp         ; Save stack pointer
  114.         and     esp,not 3       ; Align stack pointer to prevent a fault
  115.                                 ;  when we set the AC flag on a 486
  116.         pushfd                  ; Copy the EFLAGS register
  117.         pop     eax             ;   into register eax
  118.         mov     ecx,eax         ; Save the original EFLAGS value
  119.         xor     eax,40000H      ; Flip the AC flag bit
  120.         push    eax             ; Try to put the modified value back
  121.         popfd                   ;   into the EFLAGS register
  122.         pushfd                  ; Copy the EFLAGS register again
  123.         pop     eax             ;   into eax
  124.         xor     eax,ecx         ; Compare the old and new AC bits
  125.         shr     eax,18          ; Shift and mask to get the AC comparison bit
  126.         and     eax,1           ;   in the low order position of eax
  127.         push    ecx
  128.         popfd                   ; Restore EFLAGS that were saved on entry
  129.         mov     esp,edx         ; And restore stack pointer to saved value
  130.         mov     bx,ax           ; and move into bx
  131.  
  132. ; At this point ax = 0 for a 386, or ax = 1 for a 486
  133.  
  134.         test    bx,bx
  135.         jnz     @@Check586      ; Check for the presence of a Pentium(tm)
  136.         mov     _ax,CPU386
  137.         jnz     @@TestPROT      ; We have a 386
  138.  
  139. @@Check586:
  140.  
  141. ; Distinguish between the i486 and Pentium by the ability to set the ID flag
  142. ; in the EFLAGS register. If the ID flag is set, then we can use the CPUID
  143. ; instruction to determine the final version of the chip. Otherwise we
  144. ; simply have an 80486.
  145.  
  146.         pushfd                  ; push original EFLAGS
  147.         pop     eax             ; get original EFLAGS in eax
  148.         mov     ecx,eax         ; save original EFLAGS in ecx
  149.         or      eax,200000h     ; flip ID bit in EFLAGS
  150.         push    eax             ; save for EFLAGS
  151.         popfd                   ; copy to EFLAGS
  152.         pushfd                  ; push EFLAGS
  153.         pop     eax             ; get new EFLAGS value
  154.         xor     eax,ecx
  155.         mov        _ax,CPU486
  156.         jz        @@TestProt        ; We have an old i486 (flag would not set)
  157.  
  158. ; Now execute the CPUID instruction to determine the vendor, family, model
  159. ; and stepping (some new 486's answer to the CPUID test also).
  160.  
  161.         mov     eax,1           ; set up for CPUID instruction
  162. ;       cpuid
  163. db      0Fh, 0A2h               ; Opcodes for CPUID instruction
  164.         and     eax,0F00H       ; mask everything but family
  165.         shr     eax,8
  166.         cmp        al,5
  167.         mov        _ax,CPU486
  168.         jl        @@TestProt        ; We have an i486
  169.         mov     _ax,CPU586      ; We have a Pentium(tm)
  170.  
  171. @@TestPROT:
  172.         smsw    cx              ; protected? machine status -> cx
  173.         ror     cx,1            ; protection bit -> carry flag
  174.         jnc     @@Done          ; Real mode if no carry
  175.         inc     _ax             ; Protected: return value + 1
  176.  
  177. @@Done:
  178.         mov     [cpu],ax           ; Save CPU type in code segment variable
  179.         pop     bp              ; Restore bp
  180.         pop        bx
  181.         ret                     ; We are done
  182.  
  183. procend     _queryCpu
  184.  
  185. ;----------------------------------------------------------------------------
  186. ; fpu_type queryFpu(void)
  187. ;----------------------------------------------------------------------------
  188. ; Determine type of floating point coprocessor present in the system.
  189. ; The idea is to determine whether or not the floating-point control word
  190. ; can be successfully read. If it cannot, then no coprocessor exists.
  191. ; If it can the correct coprocessor is then determined depending on the
  192. ; main CPU id.
  193. ;----------------------------------------------------------------------------
  194. procstart   _queryFpu
  195.  
  196.         LOCAL   ndp_cw:WORD, ndp_sw:WORD = LocalSize
  197.  
  198.         push    _bp
  199.         mov        _bp,_sp
  200.         sub        _sp,LocalSize
  201.         push    bx
  202.  
  203.         mov     bx,FPUNONE      ; Default to no FPU present
  204.  
  205. ; The next two 80x87 instructions cannot carry the WAIT prefix,
  206. ; because there may not be an 80x87 for which to wait.  The WAIT is
  207. ; therefore emulated with a MOV <E>CX,<value> LOOP $ combination.
  208.  
  209.         mov     [ndp_cw],0      ; Clear the control word in memory
  210.         cli                     ; Interrupts must be off during test
  211.  
  212.         fninit                  ; reset NDP status word
  213.         mov     _cx,2              ; Wait for co-pro to complete operation
  214.         loop    $
  215.  
  216.         fnstcw  [ndp_cw]        ; Obtain the processor control word
  217.         mov     _cx,14h            ; Wait for co-pro to complete operation
  218.         loop    $
  219.  
  220.         sti                     ; Re-enable interrupts
  221.  
  222. ; We check to see that the precison control bits of the control word
  223. ; indicate 64 bit internal precision (bits 8 & 9 set) which is the default
  224. ; set up by the fninit instruction above. We also test that the exception
  225. ; masks are properly set.
  226.  
  227.         mov     ax,[ndp_cw]     ; AX := NDP control word
  228.         and     ax,033fh        ; Mask out the precision control bits etc.
  229.         cmp     ax,033fh        ; is the NDP present?
  230.         jne     @@Done          ; No, we are all done... (must be a 3)
  231.  
  232. ; Determine the type of NDP from the main CPU type
  233.  
  234.         mov     bx,FPU87        ; Start with the 8087 NDP
  235.         mov     ax,[cpu]        ; Get current cpu type
  236.         cmp     ax,CPU286       ; >= 80286 type processor?
  237.         jge     @@80286         ; Yes, check for 287/387/487
  238.         jmp     @@Done          ; No, we are done
  239.  
  240. ; Now that we know we have a possible co-processor and the processor is
  241. ; at least an 80286, we can check to see if coprocessor emulation software
  242. ; is installed in the system. Some emulators such as FRANKIE.387 emulate
  243. ; the co-processor so well that the above checks believe a co-pro is
  244. ; actually out there.
  245.  
  246. @@80286:
  247.         smsw    ax              ; AX := machine status word
  248.         test    al,4            ; Check the EM bit status
  249.         jnz     @@Done          ; Software emulation installed on INT 7!
  250.  
  251.         mov     ax,[cpu]        ; AX := current CPU flag
  252.         cmp     ax,CPU386       ; Do we have a 386 or above?
  253.         jge     @@80386         ; Yes, check for it
  254.         mov     bx,FPU287       ; We have a 80287 co-pro
  255.         jmp     @@Done
  256.  
  257. @@80386:
  258.         cmp     ax,CPU486       ; Do we have a 486 or above?
  259.         jge     @@80486         ; Yes, check for it
  260.  
  261. ; The i386 processor can work with either an 80287 or 80387 co processor
  262. ; so we must check for that here. The 387 says that +inf <> -inf while
  263. ; the 287 says that they are the same.
  264.  
  265.         fld1                    ; Load +1.0 onto NDP stack
  266.         fldz                    ; Load +0.0 onto NDP stack
  267.         fdiv                    ; do +1/0 (create +inf)
  268.         fld1                    ; Load +1.0 onto NDP stack
  269.         fchs                    ; Change to -1.0
  270.         fldz                    ; Load +0.0 onto NDP stack
  271.         fdiv                    ; do -1/0 (create -inf)
  272.         fcompp                  ; compare and pop values from stack
  273.         fstsw   [ndp_sw]        ; Get the status word from the co pro
  274.         mov     ax,[ndp_sw]     ; AX := Status word
  275.         and     ah,41h          ; Mask out C3 and C0 condition codes
  276.         cmp     ah,40h          ; C3 = 1, C0 = 0 means ST(0) == ST(1)
  277.         mov     bx,FPU287       ; Set up for a 287 co pro
  278.         je      @@Done          ; Yes, we were correct
  279.  
  280.         mov     bx,FPU387       ; No, it was an 80387
  281.         jmp     @@Done
  282.  
  283. @@80486:
  284.         mov     bx,FPU487       ; We must have a 487 co pro.
  285.         cmp        ax,CPU586
  286.         jl        @@Done
  287.  
  288.         mov        bx,FPU587        ; We must have a Pentium co pro.
  289.  
  290. @@Done:
  291.         xor        _ax,_ax
  292.         mov     ax,bx           ; Return FPU type in AX
  293.         pop        bx
  294.         mov        _sp,_bp
  295.         pop        _bp
  296.         ret                     ; We are done
  297.  
  298. procend     _queryFpu
  299.  
  300. endcodeseg  cpu
  301.  
  302.         END                     ; End of module
  303.